package crl.encrypt
{
	import com.swfwire.decompiler.abc.ABCFile;
	import com.swfwire.decompiler.abc.instructions.IInstruction;
	import com.swfwire.decompiler.abc.instructions.Instruction_construct;
	import com.swfwire.decompiler.abc.instructions.Instruction_debugfile;
	import com.swfwire.decompiler.abc.instructions.Instruction_dxns;
	import com.swfwire.decompiler.abc.instructions.Instruction_pushstring;
	import com.swfwire.decompiler.abc.tokens.ConstantPoolToken;
	import com.swfwire.decompiler.abc.tokens.MethodBodyInfoToken;
	import com.swfwire.decompiler.abc.tokens.StringToken;
	import com.swfwire.decompiler.data.swf.SWF;
	import com.swfwire.decompiler.data.swf.records.SymbolClassRecord;
	import com.swfwire.decompiler.data.swf.tags.SWFTag;
	import com.swfwire.decompiler.data.swf9.tags.DoABCTag;
	import com.swfwire.decompiler.data.swf9.tags.SymbolClassTag;
	
	import crl.encrypt.ext.PlayerGlobalDefine;
	import crl.encrypt.ignores.AbsIgnore;
	import crl.encrypt.ignores.InstanceIgnoreInfo;
	import crl.encrypt.ignores.StringIgnoreInfo;
	import crl.encrypt.inject.IInject;
	import crl.encrypt.inject.Inject;
	
	import flash.utils.Dictionary;

	/**
	 * 
	 * @author crl
	 * 
	 */	
	public class EncryptFactory
	{
		private var parsers:Vector.<AbsIgnore>=new Vector.<AbsIgnore>();
		private var injects:Vector.<IInject>=new Vector.<IInject>();
		public function EncryptFactory()
		{
			//registerIgnorer(new StringIgnoreInfo());
			registerIgnorer(new InstanceIgnoreInfo());
			//registerInject(new Inject());
		}
		
		public function start(swf:SWF,fileName:String):void{
			var names:Array;
			var name:String;
			var len:int,i:int;
			var replaceCoder:ReplaceCoder;
			
			var abcFiles:Vector.<ABCFile>=new Vector.<ABCFile>();
			var symbolClassRecordDic:Dictionary=new Dictionary();
			var innerString:Dictionary=new Dictionary;
			innerString[fileName]=1;
			
			var doABCTag:DoABCTag;
			for each(var tag:SWFTag in swf.tags){
				if(tag is DoABCTag){
					doABCTag=tag as DoABCTag;
					abcFiles.push(doABCTag.abcFile);
				}else if(tag is SymbolClassTag){
					for each(var symbol:SymbolClassRecord in tag["symbols"]){
						names=symbol.className.split(".");
						len=names.length;
						
						innerString[names[len-1]]=1;
						names.pop();
						innerString[names.join(".")]=1;
						//name=names[len-1];
						//if(innerString.indexOf(name)==-1)innerString.push(name);
						//if(len>1)symbolClassRecordDic[symbol]=names;
					}
				}
			}
			
			
			if(abcFiles.length==0){
				return;
			}
			
			var abc:ABCFile;
			var constantPool:ConstantPoolToken;
			
			for each(abc in abcFiles){
				constantPool=abc.cpool
				getNativeAndInnerStringList(abc,innerString);
			}
			replaceCoder=new ReplaceCoder(innerString);
			
			var ignore:AbsIgnore;
			var inject:IInject;
			
			for each(ignore in parsers){
				ignore.reset(replaceCoder);
			}
			
			/*for each(inject in injects){
				inject.reset();
			}*/
			
			
			for each(abc in abcFiles){
				for each(ignore in parsers){
					ignore.start(abc);
				}
				
				for each(inject in injects){
					inject.injectABC(abc);
				}
			}
			
			
			for each(ignore in parsers){
				ignore.end();
			}
			
			for each(inject in injects){
				inject.end();
			}
			
			
			var sTag:SymbolClassRecord;
			for(var t:* in symbolClassRecordDic){
				sTag=t;
				names=symbolClassRecordDic[sTag];
				
				for(i=0;i<len;i++){
					name=replaceCoder.replacedDic[names[i]];
					if(name)names[i]=name;
				}
				
				sTag.className=names.join(".");
			}
			
			
		}
		
		public function registerIgnorer(ignore:AbsIgnore):void{
			parsers.push(ignore);
		}
		
		public function registerInject(inject:IInject):void{
			injects.push(inject);
		}
		
		
		
		
		/**
		 * 取出代码中含有的string; 
		 * @return 
		 * 
		 */		
		public static function getNativeAndInnerStringList(abc:ABCFile,innerStrings:Dictionary):void{
			if(innerStrings==null){
				innerStrings=new Dictionary();
			}
			var stringkeys:Dictionary=new Dictionary();
			
			var cpoolString:Vector.<StringToken>=abc.cpool.strings;
			var methodBodies:Vector.<MethodBodyInfoToken>=abc.methodBodies;
			
			var els:Dictionary=new Dictionary();
			els[Instruction_pushstring]=1;
			els[Instruction_debugfile]=1;
			//els[Instruction_construct]=1;
			els[Instruction_dxns]=1;
			
			var opcodes:Vector.<IInstruction>;
			var op:IInstruction;
			var opcodeName:String;
			for each(var body:MethodBodyInfoToken in methodBodies){
				opcodes=body.instructions;
				
				for each(op in opcodes){
					if(op is Instruction_pushstring || op is Instruction_debugfile || op is Instruction_dxns){
						
						var token:StringToken=cpoolString[op["index"]]
						if(token)stringkeys[token.utf8]=1;
					}
				}
			}
			
			for(var key:String in stringkeys){
				innerStrings[key]=1;
			}
			
		}
		
		
	}
}